using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Speedball2 {
  public class Stars {
    private int _bitsTeam1;
    private int _bitsTeam2;
    private int [] _spritesIndexTeam1;
    private int [] _spritesIndexTeam2;
    //private const int _spritesIndexLeftAddress = 0x67F;
    //private const int _spritesIndexLeftAddress = 0x6A8;

    public Stars () {
      _bitsTeam1 = 0;
      _bitsTeam2 = 0;
      _spritesIndexTeam1 = new int [] { 6, 6, 6, 6, 6 };
      _spritesIndexTeam2 = new int [] { -6, -6, -6, -6, -6 };
    }

    public void CheckHit (Match match) {
      if (match.EntityHoldingBall != null)
        if (match.EntityHoldingBall._pThink != 0xF078)
          return;
      Entity ball = match.EntityBall;
      bool starsOfTeam1;
      int starIndex;
      if (ball._terrainXY.X <= 32) {
        if ((ball._terrainXY.Y < 384) || (ball._terrainXY.Y >= 544))
          return;
        starIndex = (ball._terrainXY.Y - 384) / 32;
        if (_spritesIndexTeam1 [0] >= 0)
          starsOfTeam1 = true;
        else
          starsOfTeam1 = false;
      }
      else if (ball._terrainXY.X >= 608) {
        if ((ball._terrainXY.Y < 608) || (ball._terrainXY.Y >= 768))
          return;
        starIndex = (ball._terrainXY.Y - 608) / 32;
        if (_spritesIndexTeam1 [0] < 0)
          starsOfTeam1 = true;
        else
          starsOfTeam1 = false;
      }
      else
        return;

      if (match.PlayerThrower.Bit3_IsTeam1_IsElectrobounced) {
        if (starsOfTeam1)
          ActivateTeam1 (match, starIndex);
        else
          if (TestBit (_bitsTeam2, starIndex)) {
            InactivateTeam2 (starIndex);
            match.ScoreTeam2 -= 2;
            match.DrawStatusScores ();
          }
      }
      else {
        if (!starsOfTeam1)
          ActivateTeam2 (match, starIndex);
        else
          if (TestBit (_bitsTeam1, starIndex)) {
            InactivateTeam1 (starIndex);
            match.ScoreTeam1 -= 2;
            match.DrawStatusScores ();
          }
      }
    }

    public void CheckFullRowActivated (Match match) {
      if (_bitsTeam1 == 31) {
        for (int i = 0; i < 5; i++)
          InactivateTeam1 (i);
        match.IncScoreWithBonusPoints (true, 10);
        match.DrawStatusScores ();
      }
      if (_bitsTeam2 == 31) {
        for (int i = 0; i < 5; i++)
          InactivateTeam2 (i);
        match.IncScoreWithBonusPoints (false, 10);
        match.DrawStatusScores ();
      }
    }

    private void ActivateTeam1 (Match match, int starIndex) {
      if (TestBit (_bitsTeam1, starIndex))
        return;
      SetBit (ref _bitsTeam1, starIndex);
      if (_spritesIndexTeam1 [starIndex] >= 0)
        _spritesIndexTeam1 [starIndex]++;
      else
        _spritesIndexTeam1 [starIndex]--;
      match.IncScoreWithBonusPoints (true, 2);
      match.DrawStatusScores ();
    }

    private void ActivateTeam2 (Match match, int starIndex) {
      if (TestBit (_bitsTeam2, starIndex))
        return;
      SetBit (ref _bitsTeam2, starIndex);
      if (_spritesIndexTeam2 [starIndex] >= 0)
        _spritesIndexTeam2 [starIndex] += 2;
      else
        _spritesIndexTeam2 [starIndex] -= 2;
      match.IncScoreWithBonusPoints (false, 2);
      match.DrawStatusScores ();
    }

    private void InactivateTeam1 (int starIndex) {
      if (!TestBit (_bitsTeam1, starIndex))
        return;
      UnsetBit (ref _bitsTeam1, starIndex);
      if (_spritesIndexTeam1 [starIndex] >= 0)
        _spritesIndexTeam1 [starIndex]--;
      else
        _spritesIndexTeam1 [starIndex]++;
    }

    private void InactivateTeam2 (int starIndex) {
      if (!TestBit (_bitsTeam2, starIndex))
        return;
      UnsetBit (ref _bitsTeam2, starIndex);
      if (_spritesIndexTeam2 [starIndex] >= 0)
        _spritesIndexTeam2 [starIndex] -= 2;
      else
        _spritesIndexTeam2 [starIndex] += 2;
    }

    public void Draw (Match match) {
      List<Bitmap> fieldBitmaps = SpriteManager.GetBank (BankEnum.PitchDat);
      //List<Bitmap> wallLeft = BankManager.Banks [0x549EA].GetBitmaps ();
      //List<Bitmap> wallRight = BankManager.Banks [0x565EA].GetBitmaps ();

      int [] spritesIndexLeft;
      if (_spritesIndexTeam1 [0] >= 0)
        spritesIndexLeft = _spritesIndexTeam1;
      else
        spritesIndexLeft = _spritesIndexTeam2;

      int [] spritesIndexRight;
      if (_spritesIndexTeam1 [0] < 0)
        spritesIndexRight = _spritesIndexTeam1;
      else
        spritesIndexRight = _spritesIndexTeam2;

      if (SpriteManager.Version == VersionEnum.Atari) {
        for (int i = 0; i < 5; i++) {
          int starType = Math.Abs (spritesIndexLeft [i]) - 6 - 1;
          if (starType >= 0) {
            Bitmap bitmap = fieldBitmaps [SpriteManager.WallLeftIndex + 6 + starType];
            match.DrawTile (bitmap, 0, 12 + i);
          }
        }
        for (int i = 0; i < 5; i++) {
          int starType = Math.Abs (spritesIndexRight [i]) - 6 - 1;
          if (starType >= 0) {
            Bitmap bitmap = fieldBitmaps [SpriteManager.WallRightIndex + 6 + starType];
            match.DrawTile (bitmap, 19, 19 + i);
          }
        }
      }
      else if (SpriteManager.Version == VersionEnum.Amiga) {
        for (int i = 0; i < 5; i++) {
          int starType = Math.Abs (spritesIndexLeft [i]) - 6 - 1;
          if (starType >= 0) {
            match.DrawTileAmiga (fieldBitmaps [358 + starType * 2], 0, (12 + i) * 2);
            match.DrawTileAmiga (fieldBitmaps [358 + starType * 2 + 1], 1, (12 + i) * 2);
            match.DrawTileAmiga (fieldBitmaps [366 + starType * 2], 0, (12 + i) * 2 + 1);
            match.DrawTileAmiga (fieldBitmaps [366 + starType * 2 + 1], 1, (12 + i) * 2 + 1);
          }
        }
        for (int i = 0; i < 5; i++) {
          int starType = Math.Abs (spritesIndexRight [i]) - 6 - 1;
          if (starType >= 0) {
            match.DrawTileAmiga (fieldBitmaps [362 + starType * 2], 19 * 2, (19 + i) * 2);
            match.DrawTileAmiga (fieldBitmaps [362 + starType * 2 + 1], 19 * 2 + 1, (19 + i) * 2);
            match.DrawTileAmiga (fieldBitmaps [370 + starType * 2], 19 * 2, (19 + i) * 2 + 1);
            match.DrawTileAmiga (fieldBitmaps [370 + starType * 2 + 1], 19 * 2 + 1, (19 + i) * 2 + 1);
          }
        }
      }
      else
        throw new Exception ();
    }

    public void SwitchSide () {
      for (int i = 0; i < 5; i++)
        InactivateTeam1 (i);
      for (int i = 0; i < 5; i++)
        InactivateTeam2 (i);
      ExtensionMethods.Swap (ref _spritesIndexTeam1, ref _spritesIndexTeam2);
    }

    private bool TestBit (int bits, int bitIndex) {
      return (((bits >> bitIndex) & 1) == 1);
    }

    private void SetBit (ref int bits, int bitIndex) {
      bits |= (1 << bitIndex);
    }

    private void UnsetBit (ref int bits, int bitIndex) {
      bits &= (~(1 << bitIndex)) & 31;
    }

    private void CheckHitOne (Match match, Entity bounceDome) {
      Entity ball = match.EntityBall;
      int deltaY = Math.Abs (ball._terrainXY.Y - bounceDome._terrainXY.Y);
      if (deltaY > 16)
        return;
      int deltaX = Math.Abs (ball._terrainXY.X - bounceDome._terrainXY.X);
      if (deltaX > 16)
        return;
      Point vector;
      if (bounceDome.CalcVector (ball._terrainXY, out vector) > 16)
        return;
      bounceDome._opcodeIndex = 0;
      DirBits dirBits = bounceDome.GetDirBitsToTargetBetter (ball._terrainXY);
      if (dirBits.HasNoDirection)
        return;
      ball._dir = Entity.GetDirFromDirBits (dirBits);
      ball._velocityXY = Match.GetVelocityXYFromDir (ball._dir, 8);
      ball._opcodeIndex = 0;
      match.SetBallSpeedFromThr (match.PlayerThrower._attributes._thr);
      match.IncScoreWithBonusPoints (match.PlayerThrower.Bit3_IsTeam1_IsElectrobounced, 2);
      match.DrawStatusScores ();
    }
  }
}
